<?php
/**
 * Copyright 2010 Dave Keen
 * http://www.actionscriptdeveloper.co.uk
 * 
 * This file is part of Flextrine.
 * 
 * Flextrine is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * and the Lesser GNU General Public License along with this program.
 * If not, see <http://www.gnu.org/licenses/>.
 * 
 */

namespace Flextrine\Tools;

use \Doctrine\ORM\Mapping\ClassMetadata;

require_once('vlib/vlibTemplate.php'); 

class AS3EntityGenerator {
	
	private $classesMetadata;

	function __construct($classesMetadata) {
		$this->classesMetadata = $classesMetadata;
	}
	
	public function generate() {
		$generatedClasses = array();
		foreach ($this->classesMetadata as $classMetadata) {
			$generatedClasses[str_replace("\\", "/", $classMetadata->name."EntityBase.as")] = $this->_generateBase($classMetadata);
			$generatedClasses[str_replace("\\", "/", $classMetadata->name.".as")] = $this->_generateChild($classMetadata);
		}
		
		return $generatedClasses;
	}
	
	private function _generateBase($classMetadata) {
		$template = new \vlibTemplate(dirname(__FILE__)."/entitybase.as.tpl");
		
		// Set the package, remote class and local class name
		$template->setVar("package", str_replace("\\", ".", $classMetadata->namespace));
		$template->setVar("remoteclass", str_replace("\\", "/", $classMetadata->name));
		$template->setVar("classname", $this->stripPackageFromClassName($classMetadata->name));
		
		// Get the identifiers
		$identifiers = $classMetadata->identifier;
		
		$identifiersLoop = array();
		foreach ($identifiers as $identifier)
			$identifiersLoop[] = array("identifier" => $identifier);
		
		if (sizeof($identifiersLoop) > 0) $template->setLoop("identifiersloop", $identifiersLoop);
		
		// Get the fields.  Note that id fields are always of type String.
		$fieldMappings = $classMetadata->fieldMappings;
		
		$fieldsLoop = array();
		foreach ($fieldMappings as $name => $mapping) {
			$fieldsLoop[] = array(
				"name" => $name,
				"type" => (isset($mapping['id'])) ? "String" : $this->columnTypeToAS3Type($mapping['type']),
				"id" => isset($mapping['id'])
			);
		}
		
		if (sizeof($fieldsLoop) > 0) $template->setLoop("fieldsloop", $fieldsLoop);
		
		// Get the associations
		$associationMappings = $classMetadata->associationMappings;
		
		$associationsLoop = array();
		
		foreach ($associationMappings as $name => $mapping) {
			if ($mapping["type"] & ClassMetadata::TO_ONE) {
				$type = $this->stripPackageFromClassName($mapping["targetEntity"]);
			} else if ($mapping["type"] & ClassMetadata::TO_MANY) {
				$type = "PersistentCollection";
			}
			
			$associationsLoop[] = array(
				"name" => $name,
				"type" => $type,
				"package" => str_replace("\\", ".", $mapping["targetEntity"])
			);
		}
		
		if (sizeof($associationsLoop) > 0) $template->setLoop("associationsloop", $associationsLoop);
		
		return $template->grab();
	}
	
	private function _generateChild($classMetadata) {
		$template = new \vlibTemplate(dirname(__FILE__)."/entity.as.tpl");
		
		// Set the package, remote class and local class name
		$template->setVar("package", str_replace("\\", ".", $classMetadata->namespace));
		$template->setVar("remoteclass", str_replace("\\", ".", $classMetadata->name));
		$template->setVar("classname", $this->stripPackageFromClassName($classMetadata->name));
		
		return $template->grab();
	}
	
	private function columnTypeToAS3Type($columnType) {
		switch ($columnType) {
			case "integer": // Since we can't set AS3 ints to null (they can only be 0) use a Number
			case "smallint":
				return "int";
			case "bigint":
			case "decimal":
			case "time": // There is no equivalent in AS3 so map time to a number (ms)
				return "Number";
			case "boolean":
				return "Boolean";
			case "text":
			case "string":
				return "String";
			case "date": // Date should be a normal AS3 date with HH:MM:SS == 00:00:00
			case "datetime":
				return "Date";
			default:
				return "String";
		}
	}
	
	private function stripPackageFromClassName($qualifiedClassName) {
		return preg_replace("(.*\\\\)", "", $qualifiedClassName);
	}
	
}